<div id="operations" class="section-profile">
  <div class="row">
    <div class="bottomright duk-icon"><img onclick="toggleSidebar('operations-sidebar')" src="/gui/img/expand.png"></div>
    <div class="topleft duk-icon"><img onclick="removeSection('operations')" src="/gui/img/x.png"></div>
    <div id="operations-sidebar" class="column section-border" style="flex:25%">
      <img src="/gui/img/operation.png">
      <h4>Operations</h4>
      <br>
      <div class="toggle">
        <label class="switch"><input type="checkbox" id="togBtnOp" onchange="toggleOperationView()">
          <div class="slider round"><span class="on">ADD</span><span class="off">VIEW</span></div>
        </label>
      </div>
      <p class="section-description">
        Start a new operation or review previous ones here.
      </p>
      <div id="viewOperation">
        <select id="operation-list" style="margin-bottom: 15px;" onchange="refresh();checkOpBtns()">
          <option id="operationDefault" value="" disabled selected>Operations</option>
          {% for op in operations %}
                {%  if op.start|length%}
                    <option class="operationOption" id="{{ op.id|e }}-{{ op.name|e }}" value="{{ op.id|e }}">{{ op.name|e }} - {{ op.start|e }}</option>
                {% endif %}
          {% endfor %}
        </select>
        <br>
        <center>
        <table>
            <tr>
                <td><input id="agent-output" type="checkbox"></td>
                <td><label for="agent-output"><p>&nbsp;&nbsp;include agent output</p></label></td>
            </tr>
        </table>
        </center>
        <button id="fullReportBtn" type="button" class="button-notready atomic-button" onclick="downloadOperationFullReport()">Download full report</button>
        <button id="eventLogBtn" type="button" class="button-notready atomic-button" onclick="downloadOperationEventLogs()">Download event logs</button>
        <hr>
        <button id="opDelete" type="button" class="button-notready atomic-button" onclick="deleteOperation()">Delete</button>
      </div>

      <div id="addOperation" style="display: none;">
          <input id="queueName" class="queueOption" style="opacity:0.5" disabled="true" placeholder="Operation name" oninput="checkOpformValid()"/>
          <div id="optional" class="sidebar-header">
              <h5>Basic Options</h5>
          </div>
          <div id="optional-options" class="sidebar-cutout" style="display: none">
              <select name="host" id="queueGroup" class="queueOption" style="opacity:0.5" disabled="true" onchange="checkOpformValid()">
                <option value="" class="default-option" selected>Use all groups</option>
                {% for g in groups %}
                    <option id="qgroup-{{ g|e }}" value="{{ g|e }}">{{ g|e }}</option>
                {% endfor %}
              </select>
              <select name="work" id="queueFlow" class="queueOption" style="opacity:0.5" disabled="true" onchange="advHasRepeatableAbilities(this.value)">
                <option value="" class="default-option" selected>No adversary (manual)</option>
                {% for adv in adversaries %}
                  {% if adv.has_repeatable_abilities %}
                    <option id="qflow-{{ adv.adversary_id|e }}" value="{{ adv.adversary_id|e }}" data-has-repeatable>{{ adv.name|e }}</option>
                  {% else %}
                    <option id="qflow-{{ adv.adversary_id|e }}" value="{{ adv.adversary_id|e }}">{{ adv.name|e }}</option>
                  {% endif %}
                {% endfor %}
              </select>
              <select name="phases" id="queueAutoClose" class="queueOption" style="opacity:0.5" disabled="true">
                <option value="0" selected>Keep open forever</option>
                <option value="1">Auto close operation</option>
              </select>
              <select name="state" id="queueState" class="queueOption" style="opacity:0.5" disabled="false">
                <option id="qstate-run" value="running">Run immediately</option>
                <option id="qstate-paused" value="paused">Pause on start</option>
              </select>
          </div>

          <div id="autonomous" class="sidebar-header">
              <h5>Autonomous</h5>
          </div>
          <div id="autonomous-options" class="sidebar-cutout" style="display: none;">
              <select name="autonomous" id="queueAuto" class="queueOption" style="opacity:0.5" disabled="true">
                <option value="1" selected>Run autonomously</option>
                <option value="0">Require manual approval</option>
              </select>
              <select name="planner" id="queuePlanner" class="queueOption" style="opacity:0.5;" disabled="true">
                {% for p in planners %}
                  {% if p.name == "atomic" %}
                    <option value="{{ p.name|e }}" selected>Use {{ p.name|e }} planner</option>
                  {% elif p.allow_repeatable_abilities %}
                    <option value="{{ p.name|e }}" data-allow-repeatable-abilities>Use {{ p.name|e }} planner</option>
                  {% else %}
                    <option value="{{ p.name|e }}">Use {{ p.name|e }} planner</option>
                  {% endif %}
                {% endfor %}
              </select>
              <select name="source" id="queueSource" class="queueOption" style="opacity:0.5" disabled="true">
                {% for s in sources %}
                    <option value="{{ s.name|e }}">Use {{ s.name|e }} facts</option>
                {% endfor %}
              </select>
              <select name="parsers" id="queueDefaultParsers" class="queueOption" style="opacity:0.5" disabled="true">
                <option value="1" selected>Use default parsers</option>
                <option value="0">Do not use default parsers</option>
              </select>
              <p style="margin-bottom:-10px">Cleanup Timeout (secs)</p>
              <input id="queueTimeout" class="queueOption" type="number" value="30" min="0" max="300"
                      onchange="stream('The number of seconds Caldera will wait per cleanup action to complete before continuing.')">
          </div>

          <div id="stealth" class="sidebar-header">
              <h5>Stealth</h5>
          </div>
          <div id="stealth-options" class="sidebar-cutout" style="display: none;">
              <select name="phases" id="queueObfuscated" class="queueOption" style="opacity:0.5" disabled="true">
                  {% for o in obfuscators %}
                    <option value="{{ o.name|e }}">{{ o.name|e }} obfuscation</option>
                  {% endfor %}
              </select>
              <input name="jitter" id="queueJitter" class="queueOption" placeholder="Jitter (min/max) sec" style="opacity:0.5;" disabled="true" helpinfo="jitterInfo"/>
              <p style="margin-bottom:-10px">adjust visibility: </p>
              <input id="queueVisibility" class="queueOption" type="range" value="50" min="1" max="100" onchange="stream('The higher the visibility number, the more risk you will take with your operation getting noticed by the defense.')">
          </div>

          <div id="schedules" class="sidebar-header">
              <h5>Schedule</h5>
          </div>
          <div id="schedules-options" class="sidebar-cutout" style="display: none;">
              <input type="time" id="schedule-time" onchange="checkOpformValid()">
              <button id="scheduleBtn" type="button" style="opacity:0.5;" disabled="true" class="button-notready atomic-button" onclick="handleScheduleAction()">
                  Schedule
              </button>
          </div>
      </div>
      <button id="opBtn" type="button" style="opacity:0.5" disabled="true" class="button-notready atomic-button" onclick="handleStartAction()">
          Start
      </button>
    </div>
    <div class="column op-selected" style="flex:75%">
      <div class="op-dets">
        <center>
            <span title="Current Operation Status" class="op-control-text" id="op-control-state">
                <div id="op-control-info-wrapper">
                    <div id="op-control-info-status" class="op-control-info-entry" style="border-right: 2px solid"></div>
                    <div id="op-control-info-start" class="op-control-info-entry" style="border-right: 2px solid"></div>
                    <div id="op-control-info-length" class="op-control-info-entry"></div>
                </div>
            </span>
            <br><br>
            <div class="op-control-container">
                <span title="Complete Operation" class="op-control-item"><button id="op-control-stop" onclick="changeCurrentOperationState('cleanup')">&#9632;</button></span>
                <span title="Pause Operation" class="op-control-item"><button id="op-control-pause" onclick="changeCurrentOperationState('paused')">&#2405;</button></span>
                <span title="Run One Step" class="op-control-item"><button id="run-one-link" onclick="changeCurrentOperationState('run_one_link')">&#9658;&#10072;</button></span>
                <span title="Run Operation" class="op-control-item"><button id="op-control-run" onclick="changeCurrentOperationState('running')">&#9658;</button></span>
                <br>
                <div class="toggle">
                    <label class="switch"><input type="checkbox" id="togBtnHil" onchange="toggleHil()">
                        <div class="slider round"><span class="on">Autonomous&emsp;&emsp;</span><span class="off">Manual</span></div>
                    </label>
                </div>
            </div>
            <br>
            <table class="legend">
              <tr>
                  <td class="queued">queued</td>
                  <td class="collected">collected</td>
                  <td class="success">success</td>
                  <td class="failure">failure</td>
                  <td class="timeout">timeout</td>
                  <td class="discarded">discarded</td>
                  <td class="untrusted">untrusted</td>
                  <td class="visibility">visible</td>
              </tr>
            </table>
            <br>
            <div>
                <select id="currentObfuscation" onchange="updateObfuscation()" class="dark-select" style="width:33%">
                  {% for o in obfuscators %}
                    <option value="{{ o.name|e }}">Use {{ o.name|e }} obfuscation</option>
                  {% endfor %}
              </select>
            </div>
        </center>
      </div>
      <div id="content">
          <span class="op-potential-links" onclick="document.getElementById('potential-modal').style.display='block';">&#10010; potential links</span>
          <span class="op-manual-commands" onclick="document.getElementById('manual-modal').style.display='block';">&#10010; manual command</span>
          <br>
          <ul id="timeline" class="timeline">
              <li id="time-start">
          </ul>
      </div>
    </div>
  </div>
</div>

<div id="more-modal" class="modal">
    <form class="modal-content ability-viewer">
        <div class="imgcontainer">
          <span onclick="resetMoreModal();" class="close" title="Close Modal">&times;</span>
        </div>
        <div class="container" style="text-align:left">
            <code id="resultCmd"></code>
            <hr>
            <pre id="resultView" style="text-align: left;max-width:800px;"></pre>
        </div>
    </form>
</div>

<div id="potential-modal" class="modal">
    <div class="modal-content" style="width:100%;">
        <div class="container section-profile row ability-viewer modal-box">
            <div class="column control-width" style="flex:100%;">
                <select id="potential-agent-filter" onchange="fetchPotentialLinks('potential-modal');">
                    <option disabled selected>Choose an agent</option>
                </select>
                <select id="potential-link-tactic-filter" onchange="updateTacticFilter('potential-modal');">
                    <option disabled selected>Choose a tactic</option>
                    <option selected value="-- any --">-- any --</option>
                </select>
                <select id="potential-link-technique-filter" onchange="updateTechniqueFilter('potential-modal');">
                    <option disabled selected>Choose an technique</option>
                    <option selected value="-- any --">-- any --</option>
                </select>
                <h2 id="potential-links-count"></h2>
                <ul id="potential-links"></ul>
            </div>
            <div class="imgcontainer">
                <span onclick="closePotentialLinksModal()" class="close" title="Close Modal">&times;</span>
            </div>
        </div>
    </div>
</div>

<div id="manual-modal" class="modal">
    <div class="modal-content" style="width:100%;">
        <div class="container section-profile row ability-viewer modal-box">
            <div class="column control-width" style="flex:100%;">
                <select id="manual-agent" onchange="selectManualAgent();">
                    <option disabled selected>Choose an agent</option>
                </select>
                <div id="manual-command-settings" style="display:none">
                  <select id="manual-executor"></select>
                  <input type="text" id="manual-command" placeholder="Run arbitrary command" />
                  <button id="manual-run" type="button" class="button-success atomic-button" onclick="runManualCommand()">Run</button>
                </div>
            </div>
            <div class="imgcontainer">
                <span onclick="closeManualCommandModal()" class="close" title="Close Modal">&times;</span>
            </div>
        </div>
    </div>
</div>

<li id="potential-link-template" class="potential-links" style="display: none;margin-bottom:-50px">
    <div class="row-simple">
        <div class="column">
            <hr>
            <table frame=void style="border-spacing:5px;border-collapse:separate;width:100%;">
                <tr>
                    <td><b>name:</b></td>
                    <td><p id="potential-name"></td>
                    <td><button class="button-success potential-button" onclick="addLink($(this))">add</button></td>
                </tr>
                <tr>
                    <td><b>technique:</b></td>
                    <td><p id="potential-technique"></td>
                </tr>
                <tr>
                    <td><b>description:</b></td>
                    <td><p id="potential-description" style="white-space:pre-wrap;font-family:monospace;font-size:13px;overflow:auto;display:block;"></td>
                </tr>
                <tr>
                    <td><b>command:</b></td>
                    <td><code contenteditable="true" id="potential-command"></code></td>
                </tr>
                <tr>
                    <td><b>score:</b></td>
                    <td><p contenteditable="false" id="potential-score"></p></td>
                </tr>
                <tr>
                    <td><b>visibility:</b></td>
                    <td><p contenteditable="false" id="potential-visibility"></p></td>
                </tr>
            </table>
        </div>
    </div>
</li>

<li id="link-template" class="event" data-date="" style="display: none">
  <div class="member-infos">
    <h1 id="time-tactic" class="member-title"></h1>
    <div id="inner-contents">
      <div id="decision-card" class="decision-card">
        <table style="border-spacing:15px;">
        </table>
      </div>
    </div>
  </div>
</li>

<div id="loop-template" class="loop-section" style="display:none">
    <div style="display:flex">
        <div class="column" style="flex:15%; margin:5px">
            <button class="atomic-button button-success approve" type="button" onclick="submitHilChanges(this, -3)" style="margin: 5px">Approve</button>
            <button class="atomic-button button-embedded discard" type="button" onclick="submitHilChanges(this, -2)" style="margin: 5px;margin-bottom: 15px">Discard</button>
        </div>
        <div class="column codearea" style="flex:85%; margin:5px">
            <p class="hil-linkId" style="display:none"></p>
            <div class="hil-command" role="textbox" contenteditable spellcheck="false"></div>
        </div>
    </div>
</div>

<script>
    let refresher = setInterval(refresh, 10000);
    $('.section-profile').bind('destroyed', function() {
        clearInterval(refresher);
    });

    $(document).ready(function(){
        stream('Want to run a new operation? If you have at least 1 agent deployed, click the "View" toggle button.')

        $("#optional").click(function(){
            stream('Basic options are your most likely to modify. Note, if you select no group, all agents will be in scope.');
            $("#optional-options").slideToggle();
        });
        $("#schedules").click(function(){
            stream('Schedule your operation to run every day.');
            $("#schedules-options").slideToggle();
            $('#opBtn').fadeToggle('slow');
        });
        $("#stealth").click(function(){
            stream('Stealth options will determine just how noticeable your operation is to the defense.');
            $("#stealth-options").slideToggle();
        });
        $("#autonomous").click(function(){
            stream('Autonomous options allow you to configure how much manual intervention you want.');
            $("#autonomous-options").slideToggle();
        });
    });

    function toggleOperationView() {
        $('#viewOperation').toggle();
        $('#addOperation').toggle();

        if ($('#togBtnOp').is(':checked')) {
            stream('Operation name required. Click the headers below to reveal optional properties.');
            showHide('.queueOption,#opBtn,#scheduleBtn', '#operation-list');
            $('#opBtn').addClass('separated-button');
            checkOpformValid();
        } else {
            showHide('#operation-list', '.queueOption,#opBtn,#scheduleBtn');
            $('#opBtn').removeClass('separated-button');
        }
    }

    function handleStartAction(){
        $('.op-selected').css('visibility', 'hidden');
        restRequest('PUT', buildOperationObject(), handleStartActionCallback);
    }

    function checkOpBtns(){
        validateFormState(($('#operation-list').val()), '#opDelete');
        validateFormState(($('#operation-list').val()), '#fullReportBtn');
        validateFormState(($('#operation-list').val()), '#eventLogBtn');
    }

    function deleteOperation(){
        function deleteCallback(data){
            // Remove operation from main view
            $('.op-selected').css('visibility', 'hidden');
            
            // Remove operation from sidebar dropdown
            $('#operation-list option[value="' + operation_id + '"]').remove();
            $('#operationDefault').prop('selected', true);

            // Change sidebar button color
            checkOpBtns();

            stream(data);
        }
        let operation_id = $('#operation-list option:selected').attr('value');
        let data = {'index': 'operations', 'id': operation_id};
        restRequest('DELETE', data, deleteCallback);
    }

    function handleScheduleAction(){
        let op = buildOperationObject();
        let time = document.getElementById("schedule-time").value;
        restRequest('PUT', {'index': 'schedule', 'operation': op, 'schedule':
                {'hour': parseInt(time.split(":")[0]), 'minute': parseInt(time.split(":")[1])}}, doNothing);
        stream('New operation scheduled!');
    }

    function buildOperationObject() {
        let name = document.getElementById("queueName").value;
        if(!name){ warn('Please enter an operation name'); return; }

        let jitter = document.getElementById("queueJitter").value || "4/8";
        try {
            let [jitterMin, jitterMax] = jitter.split("/");
            jitterMin = parseInt(jitterMin);
            jitterMax = parseInt(jitterMax);
            if(!jitterMin || !jitterMax){
                throw true;
            }
            if(jitterMin >= jitterMax){
                warn('Jitter MIN must be less than the jitter MAX.');
                return;
            }
        } catch (e) {
            warn('Jitter must be of the form "min/max" (e.x. 4/8)');
            return;
        }
        return {
            "index": "operations",
            "name":name,
            "group":document.getElementById("queueGroup").value,
            "adversary_id":document.getElementById("queueFlow").value,
            "state":document.getElementById("queueState").value,
            "planner":document.getElementById("queuePlanner").value,
            "autonomous":document.getElementById("queueAuto").value,
            "obfuscator":document.getElementById("queueObfuscated").value,
            "auto_close": document.getElementById("queueAutoClose").value,
            "use_learning_parsers": document.getElementById("queueDefaultParsers").value,
            "jitter":jitter,
            "source":document.getElementById("queueSource").value,
            "visibility": document.getElementById("queueVisibility").value,
            "timeout": document.getElementById("queueTimeout").value
        };
    }

    function changeCurrentOperationState(newState){
        let op_id = $('#operation-list option:selected').attr('value');
        stream('Changing operation state to '+newState);
        restRequest('POST', {'index':'operation','op_id': op_id, 'state': newState}, doNothing, `/api/rest`);
    }

    function updateObfuscation() {
        let op_id = $('#operation-list option:selected').attr('value');
        let newObfuscation = $('#currentObfuscation').val();
        stream('Changing operation obfuscation to '+newObfuscation);
        restRequest('POST', {'index':'operation','op_id': op_id, 'obfuscator': newObfuscation}, doNothing, `/api/rest`);
    }

    function handleStartActionCallback(data){
        $("#togBtnOp").prop("checked", false).change();
        checkOpformValid();
        stream('Notice that you can pause or stop the operation at any time. Toggle into manual mode if you want full control or click potential links to add TTPs to the operation.');
        restRequest('POST', {'index':'operations'}, reloadOperationsElements);
    }

    function reloadOperationsElements(data){
        let op_elem = $("#operation-list");
        $.each(data, function(index, op) {
            if(!op_elem.find('option[value="'+op.id+'"]').length > 0){
                op_elem.append($('<option></option>')
                    .attr('id', op.id)
                    .addClass('operationOption')
                    .val(op.id)
                    .text(op.name + ' - ' + op.start)
                );
            }
        });
        op_elem.prop('selectedIndex', op_elem.find('option').length-1).change();
    }

    function clearTimeline() {
        let selectedOperationId = $('#operation-list option:selected').attr('value');
        $('.event').each(function() {
            let opId = $(this).attr('operation');
            if(opId && opId !== selectedOperationId) {
                $(this).remove();
            }
        });
    }

    function refresh() {
        function operationCallback(data){
            let OPERATION = data[0];
            $('#op-control-info-status').text(OPERATION.state);
            $('#op-control-info-start').text(OPERATION.start);
            $('#op-control-info-length').text(OPERATION.chain.length + ' DECISIONS');
            if (OPERATION.autonomous) {
                $("#togBtnHil").prop("checked", true);
            } else {
                $("#togBtnHil").prop("checked", false);
            }
            $('#currentObfuscation').val(OPERATION.obfuscator);
            applyOperationAgents(OPERATION);
            clearTimeline();
            for (let i=0; i<OPERATION.chain.length; i++) {
                if ($("#op_id_" + OPERATION.chain[i].id).length === 0) {
                    let template = $("#link-template").clone();
                    let title = OPERATION.chain[i].ability.name;
                    if(OPERATION.chain[i].cleanup) {
                        title = title + " (CLEANUP)"
                    }
                    let agentPaw = OPERATION.chain[i].paw;
                    let lnk = OPERATION.chain[i].id;
                    template.attr("id", "op_id_" + OPERATION.chain[i].id);
                    template.attr("operation", OPERATION.id);
                    template.attr("data-date", OPERATION.chain[i].decide.split('.')[0]);
                    template.find('#time-tactic')
                        .append($('<div></div>')
                            .css('font-size', '13px')
                            .css('font-weight', '100')
                            .dblclick( () => {
                                rollup(OPERATION.chain[i].id);
                            })
                            .text('agent#' + agentPaw + '... ' + title)
                            .append($('<span></span>')
                                .attr('id', OPERATION.chain[i].id + '-rs')
                                .addClass('tactic-find-result')
                                .attr('data-encoded-cmd', OPERATION.chain[i].command)
                                .click( event => {
                                    findResults($(event.currentTarget), lnk);
                                })
                            )
                            .append($('<span style="font-size:11px;float:right;cursor:pointer;margin-left:5px"></span>')
                                .attr('id', OPERATION.chain[i].id + '-rm')
                                .click( () => {
                                    updateLinkStatus2(lnk, OPERATION.id, -2);
                                })
                                .html('&#x274C;')
                            )
                            .append($('<img style="height: 20px;border: none;float: right;cursor: pointer;margin-right: .14em" />')
                                .attr('id', OPERATION.chain[i].id + '-cm')
                                .attr('src', '/gui/img/duk.png')
                                .click( () => {
                                    showCommand(OPERATION.chain[i].command);
                                })
                            )
                            .append($('<span style="font-size:22px;float:right;cursor:pointer;"></span>')
                                .attr('id', OPERATION.chain[i].id + '-add')
                                .click( () => {
                                    updateLinkStatus2(lnk, OPERATION.id, -3);
                                })
                                .html('&#x002B;')
                            )

                        )

                    if (OPERATION.chain[i].status === -1) {
                        let loop_template = $("#loop-template").clone();
                        loop_template.removeAttr('id');
                        loop_template.find('.hil-linkId').text(OPERATION.chain[i].unique);
                        loop_template.find('.hil-command').text(b64DecodeUnicode(OPERATION.chain[i].command));
                        loop_template.css('display', 'block');
                        loop_template.insertAfter(template.find(".member-infos"));
                        template.find('#'+OPERATION.chain[i].id+'-rm').remove();
                        template.find('#'+OPERATION.chain[i].id+'-cm').remove()
                    }

                    refreshUpdatableFields(OPERATION.chain[i], template, true);

                    template.insertAfter("#time-start");
                    $(template.find("#inner-contents")).slideUp();
                    template.show();

                } else {
                    let existing = $("#op_id_"+OPERATION.chain[i].id);
                    refreshUpdatableFields(OPERATION.chain[i], existing);
                }
            }
            if(OPERATION.state == "running" && OPERATION.chain.length == 0) {
                stream("No abilities were ran. Click '+ potential links' to add new abilities to run in your operation or click the stop button to finish the operation.");
            }
            else if(OPERATION.state == "running" && OPERATION.chain.every(function(link, idx) { return link.status != -3 })) {
                stream("Abilities exhausted. Click '+ potential links' to add new abilities to run in your operation or click the stop button to finish the operation.");
            }
        }
        function updateGroups(data) {
            // Update the group dropdown list with new agent groups
            var options = $('#queueGroup option');
            var groups = $.map(options, function(option) {
                if (option.value) {
                    return option.value;
                }
            });
            $.each(data, function(index, agent) {
                if ($.inArray(agent.group, groups) === -1) {
                    var newOption = $('<option></option>')
                        .attr('id', 'qgroup-' + agent.group)
                        .attr('value', agent.group)
                        .text(agent.group);
                    $('#queueGroup').append(newOption);
                    groups.push(agent.group);
                }
            });
        }
        let selectedOperationId = $('#operation-list option:selected').attr('value');
        if(selectedOperationId !== '') {
            let postData = selectedOperationId ? {'index':'operations','id': selectedOperationId} : null;
            if (selectedOperationId != null){
                $('.op-selected').css('visibility', 'visible');
            }
            stream('Go to the GameBoard plugin to see if the blue team can detect your activities.');
            restRequest('POST', postData, operationCallback, '/api/rest');
        }
        restRequest('POST', {'index':'agents'}, updateGroups);
    }

    function applyOperationAgents(operation) {
        for(let i=0; i<operation.host_group.length; i++){
            let paw = operation.host_group[i].paw;
            if($("#potential-agent-filter option[value='agent-"+paw+"'").length === 0){
                 $('#potential-agent-filter').append($("<option></option>")
                        .attr("value", 'agent-'+paw)
                        .text(operation.host_group[i].display_name + '-'+operation.host_group[i].paw));
            }
            if($("#manual-agent option[value='" + paw + "'").length === 0){
                 $('#manual-agent').append($("<option></option>")
                        .attr('value', paw)
                        .text(operation.host_group[i].display_name + '-'+operation.host_group[i].paw)
                        .data('executors', operation.host_group[i].executors));
            }
        }
    }

    function fetchPotentialLinks() {
        $('#potential-links').empty();
        let selectedOperationId = $('#operation-list option:selected').attr('value');
        let selectedAgent = $('#potential-agent-filter option:selected').attr('value');
        let paw = selectedAgent.split('-')[1];
        let postData = {"index":"link","op_id": selectedOperationId, "paw": paw};
        restRequest('POST', postData, potentialLinksCallback, '/api/rest');
        $('#potential-links-count').text('Building potential links...');
    }

    function potentialLinksCallback(data){
        $('#potential-agent-filter option:selected').data(data);
        tacticFilter = $('#potential-link-tactic-filter option:selected').attr('value')
        techniqueFilter = $('#potential-link-technique-filter option:selected').attr('value')
        $('#potential-links').empty()
        for(let i=0; i<data.links.length; i++){
            let link = data.links[i];
            let template = $("#potential-link-template").clone();
            let uniqueLinkId = 'potential-link-template-'+link.ability.executor+'-'+link.ability.ability_id;
            if(!(tacticFilter === '-- any --' || typeof tacticFilter === 'undefined') && !(tacticFilter === ("tactic-" + link.ability.tactic)))
                continue;
            if(!(techniqueFilter === '-- any --' || typeof techniqueFilter === 'undefined') && !(techniqueFilter === ("technique-"+link.ability.technique_id)))
                continue;/**/
            template.attr('id', uniqueLinkId);
            template.find('#potential-name').text(link.ability.name);
            template.find('#potential-technique').text(link.ability.technique_id+' - '+link.ability.technique_name+' ('+link.ability.tactic+')')
            template.find('#potential-description').text(link.ability.description);
            template.find('#potential-command').text(b64DecodeUnicode(link.command));
            template.find('#potential-score').text(link.score);
            template.find('#potential-visibility').text(link.visibility.score);
            template.data('link', link);
            template.show();
            if($("#potential-link-tactic-filter option[value='tactic-"+link.ability.tactic+"'").length === 0){
                $('#potential-link-tactic-filter').append($("<option></option>")
                    .attr("value", 'tactic-'+link.ability.tactic)
                    .text(link.ability.tactic)
                );
            }
            if($("#potential-link-technique-filter option[value='technique-"+link.ability.technique_id+"'").length === 0){
                $('#potential-link-technique-filter').append($("<option></option>")
                    .attr("value", 'technique-'+link.ability.technique_id)
                    .text(link.ability.technique_id + ' - ' + link.ability.technique_name)
                );
            }
            $('#potential-links').append(template);
        }
        alphabetize_dropdown($('#potential-link-tactic-filter'));
        alphabetize_dropdown($('#potential-link-technique-filter'));
        updatePotentialLinkCount();
    }

    function updateTacticFilter() {
        $('#potential-link-technique-filter').children('option:not(:first)').remove();
        $('#potential-link-technique-filter').append($("<option></option>").text("-- any --"));/**/
        potentialLinksCallback($('#potential-agent-filter option:selected').data());
    }

    function updateTechniqueFilter() {
        potentialLinksCallback($('#potential-agent-filter option:selected').data());
    }

    function closePotentialLinksModal() {
        document.getElementById('potential-modal').style.display='none';
        $('#potential-links-count').text('');
        $('#potential-links').empty();
        $('#potential-agent-filter').prop("selectedIndex", 0);
    }

    function addLink(l) {
        let linkDiv = l.parent().parent().parent().parent().parent().parent().parent();
        let link = linkDiv.data('link');
        let uniqueLinkId = 'potential-link-template-'+link.ability.executor+'-'+link.ability.ability_id;
        link.command = b64EncodeUnicode(linkDiv.find('#potential-command').text());
        $('#'+uniqueLinkId).remove();
        updatePotentialLinkCount();
        link["index"] = "link";
        restRequest('PUT', link, refresh, '/api/rest');
    }

    function updatePotentialLinkCount(){
        $('#potential-links-count').text($('#potential-links li').length + ' potential links');
    }

    function selectManualAgent() {
        $('#manual-executor').empty();
        let executorShells = {
            'psh': 'PS >',
            'cmd': '>',
            'sh': '$'
        };
        $.each($('#manual-agent option:selected').data('executors'), function(index, executor) {
            if (executor in executorShells) {
                var newOption = $('<option></option>')
                                .attr('value', executor)
                                .text(executorShells[executor]);
                                $('#manual-executor').append(newOption);
            }
        });
        $('#manual-command-settings').show();
    }

    function closeManualCommandModal() {
        $('#manual-modal').hide();
        $('#manual-agent-filter').prop('selectedIndex', 0);
        $('#manual-command-settings').hide();
    }

    function runManualCommand() {
        function runManualCommandCallback(data) {
            if (data['error']) {
                stream('Error running manual command: ' + data['error']);
            } else {
                stream('Manual command queued');
                $('#manual-command').val('');
            }
            $('#manual-run').addClass('button-success').removeClass('button-notready');
        }
        let agent = $('#manual-agent').val();
        let operation = $('#operation-list').val();
        let executor = $('#manual-executor').val();
        let command = $('#manual-command').val();
        if (agent !== null && operation !== null && executor !== null && command !== '') {
            $('#manual-run').addClass('button-notready').removeClass('button-success');
            let request = {
                'index': 'manual_command',
                'agent': agent,
                'operation': operation,
                'executor': executor,
                'command': command
            };
            restRequest('PUT', request, runManualCommandCallback);
        }
    }

    function refreshUpdatableFields(chain, div, newEntry=false){
        if(chain.status !== -5) {
            div.find('#'+chain.id+'-add').remove();
        }
        if(chain.collect || chain.status <= -4) {
            div.find('#'+chain.id+'-rm').remove();
        }
        if(chain.finish && chain.output) {
            let resultStar = div.find('#'+chain.id+'-rs');
            if(chain.facts.length > 0){
                stream('Click the stars to view command output. Gold ones mean information was learned.');
                resultStar.removeClass('tactic-no-facts');
                resultStar.addClass('tactic-has-facts');
            } else {
                resultStar.addClass('tactic-no-facts');
            }
            div.find('#'+chain.id+'-rm').remove();
            div.find('#'+chain.id+'-cm').remove();
        }
        if(chain.status === 0) {
            applyTimelineColor(div, 'success');
        } else if (chain.status === -2) {
            div.find('#'+chain.id+'-rm').remove();
            applyTimelineColor(div, 'discarded');
        } else if (chain.status === 1) {
            applyTimelineColor(div, 'failure');
        } else if (chain.status === 124) {
            applyTimelineColor(div, 'timeout');
        } else if (chain.status === -3 && chain.collect) {
            applyTimelineColor(div, 'collected');
        } else if (chain.status === -4) {
            applyTimelineColor(div, 'untrusted');
        } else if (chain.status === -5) {
            applyTimelineColor(div, 'visibility');
        } else {
            applyTimelineColor(div, 'queued');
        }
    }

    function applyTimelineColor(div, color) {
        div.removeClass('collected');
        div.removeClass('queued');
        div.removeClass('visibility');
        div.addClass(color);
    }

    function rollup(id) {
        let inner = $("#op_id_"+id).find("#inner-contents");
        if ($("#op_id_"+id).find("#inner-contents").is(":visible")) {
            $(inner).slideUp();
        } else {
            $(inner).slideDown();
        }
    }

    function findResults(elem, lnk){
        function loadResults(data){
            if (data) {
                let res = b64DecodeUnicode(data.output);
                $('#resultView').text(res);
                resultText = $('#resultView').html();

                let factValues = Array.from(data.link.facts, fact => fact.value.toString());
                factValues = Array.from(new Set(factValues));
                factValues.sort((a, b) => { return b.length - a.length });
                $.each(factValues, (i, factValue) => {
                    let encodedValue = $('<div/>').text(factValue).html();
                    resultText = resultText.replaceAll(encodedValue, '<span class="highlight">' + encodedValue + '</span>');
                });
                $('#resultView').html(resultText);
            } else {
              $('#resultView').empty();
            }
        }
        document.getElementById('more-modal').style.display='block';
        $('#resultCmd').text(b64DecodeUnicode($(elem).attr('data-encoded-cmd')));
        restRequest('POST', {'index':'result','link_id':lnk}, loadResults);
    }

    function downloadOperationFullReport() {
        downloadOperationInfo('full-report');
    }

    function downloadOperationEventLogs() {
        downloadOperationInfo('event-logs');
    }

    function downloadOperationInfo(format) {
        let selectedOperationId = $('#operation-list option:selected').attr('value');
        let agentOutput = $('#agent-output').prop("checked");
        let postData = selectedOperationId ? {
                'index':'operation_report',
                'op_id': selectedOperationId,
                'agent_output': Number(agentOutput),
                'format': format,
            } : null;
        let selectedOpName = $('#operation-list option:selected').text();
        downloadReport('/api/rest', selectedOpName, postData);
    }

    function resetMoreModal() {
        let modal = $('#more-modal');
        modal.hide();
        modal.find('#resultCmd').text('');
        modal.find('#resultView').text('');
    }

    function submitHilChanges(link_button, status){
        link_loop = $(link_button).parent().parent();
        let command = $(link_loop).find('.hil-command').val();
        updateLinkStatus($(link_loop).find('.hil-linkId').html(), status, b64EncodeUnicode(command));
        $(link_loop).parent().parent().remove();
        refresh();
        return false;
    }

    function updateLinkStatus2(lnk, op_id, status) {
        let data = {'index':'chain', 'link_id': lnk, 'status': status};
        restRequest('PUT', data, refresh);
    }

    function updateLinkStatus(lnk, status, command='') {
        let data = {'index':'chain', 'link_id': lnk, 'status': status};
        if(command) {
            data['command'] = command;
        }
        restRequest('PUT', data, doNothing);
    }

    function toggleHil(){
        let op_id = $('#operation-list option:selected').attr('value');
        restRequest('POST', {'index':'operation','op_id': op_id,'autonomous':'toggleMe'}, doNothing, `/api/rest`);
    }

    function checkOpformValid(){
        validateFormState(($('#togBtnOp').is(':checked') && $('#queueName').val()), '#opBtn');
        validateFormState(($('#queueName').val()) && (document.getElementById("schedule-time").value !== ""), '#scheduleBtn');
        if ($('#togBtnOp').is(':checked')) {
            $('#opBtn').addClass('separated-button');
        }
    }

    function showCommand(command){
        document.getElementById('more-modal').style.display='block';
        $('#resultCmd').text(b64DecodeUnicode(command));
        $('#resultView').empty();
    }
    //# sourceURL=operations.js

    function advHasRepeatableAbilities(selectedAdversary) {
        if ($('#qflow-' + selectedAdversary).data('has-repeatable') != null) {
            $("#queuePlanner option").each(function() {
                if (!this.hasAttribute('data-allow-repeatable-abilities')) {
                    this.setAttribute('disabled', '');
                    this.removeAttribute('selected');
                }
            });
            $('#queuePlanner').val($('#queuePlanner option:not([disabled]):first').val());
            stream('The profile selected has repeatable abilities. Some planners do not support repeatable abilities and have been disabled.');
        }
        else {
            $('#queuePlanner option').each(function() { this.removeAttribute('disabled'); this.removeAttribute('selected') });
            $('#queuePlanner').val($('#queuePlanner option:not([disabled]):first').val());
            stream('Selecting first available planner: ' + $('#queuePlanner').val() + '.');
        }
    }
</script>
